🛢️ Análisis Global - Reservas de Petróleo y Gas Natural¶

Fuente: BP Statistical Review 2024 | Fecha: Enero 2025

📋 Sobre este Proyecto¶

Este notebook analiza las reservas probadas de petróleo y gas natural a nivel mundial, con explicaciones detalladas para que sea comprensible incluso sin experiencia previa en programación.

¿Qué vamos a descubrir?¶

Vamos a identificar qué países tienen las mayores reservas energéticas del planeta. Calcularemos cuántos años podrían durar estas reservas manteniendo la producción actual. Exploraremos la evolución de las reservas durante cuatro décadas (1980-2020). Y crearemos visualizaciones interactivas que revelan patrones geográficos y la relación entre producción y consumo.

Estructura¶

Módulo 1: Petróleo (gráfico Energy Analytics, mapas, análisis temporal) Módulo 2: Gas Natural (misma estructura) Módulo 3: Producción y Consumo Módulo 4: Análisis Integrado

🔧 Preparación¶

Librerías: Nuestras Herramientas¶

Las librerías son conjuntos de código ya programado que nos ahorran trabajo. Es como usar apps en vez de programarlas desde cero.

Pandas (pd): Nuestra hoja de cálculo mejorada. Maneja millones de filas eficientemente.

Plotly (px/go): Crea gráficos interactivos donde puedes hacer zoom y explorar datos.

Numpy (np): Calculadora científica para operaciones matemáticas rápidas.

In [179]:
# Importar librerías
import pandas as pd
import plotly.express as px
import plotly.graph_objects as go
from plotly.subplots import make_subplots
import numpy as np
import plotly.io as pio
pio.renderers.default = "notebook"

print("✅ Librerías listas")
✅ Librerías listas

📂 Cargar Datos¶

Los archivos CSV son tablas guardadas como texto. pd.read_csv() los convierte en DataFrames (tablas manipulables).

In [180]:
# Cargar todos los archivos
df_oil_reserves = pd.read_csv('data\Oil-Proved_Reserves.csv')
df_oil_reserves_history = pd.read_csv('data\History_Oil-Proven_Reserves.csv')  
df_oil_production = pd.read_csv('data\Oil_Production__Mbbl_.csv')
df_oil_consumption = pd.read_csv('data\Oil_Consumption.csv')

df_gas_reserves = pd.read_csv('data\Total_Proved_Reserves__Tcm_.csv')
df_gas_reserves_history = pd.read_csv('data\History_Natural_Gas_-_Proved_Reserves__Tcm_.csv')
df_gas_production = pd.read_csv('data\Gas_Production__Bcm_.csv')
df_gas_consumption = pd.read_csv('data\Gas_Consumption__Bcm_.csv')

print("✅ Datos cargados")
print(f"Petróleo: {len(df_oil_reserves)} países")
print(f"Gas: {len(df_gas_reserves)} países")
✅ Datos cargados
Petróleo: 61 países
Gas: 61 países
<>:2: SyntaxWarning:

"\O" is an invalid escape sequence. Such sequences will not work in the future. Did you mean "\\O"? A raw string is also an option.

<>:3: SyntaxWarning:

"\H" is an invalid escape sequence. Such sequences will not work in the future. Did you mean "\\H"? A raw string is also an option.

<>:4: SyntaxWarning:

"\O" is an invalid escape sequence. Such sequences will not work in the future. Did you mean "\\O"? A raw string is also an option.

<>:5: SyntaxWarning:

"\O" is an invalid escape sequence. Such sequences will not work in the future. Did you mean "\\O"? A raw string is also an option.

<>:7: SyntaxWarning:

"\T" is an invalid escape sequence. Such sequences will not work in the future. Did you mean "\\T"? A raw string is also an option.

<>:8: SyntaxWarning:

"\H" is an invalid escape sequence. Such sequences will not work in the future. Did you mean "\\H"? A raw string is also an option.

<>:9: SyntaxWarning:

"\G" is an invalid escape sequence. Such sequences will not work in the future. Did you mean "\\G"? A raw string is also an option.

<>:10: SyntaxWarning:

"\G" is an invalid escape sequence. Such sequences will not work in the future. Did you mean "\\G"? A raw string is also an option.

<>:2: SyntaxWarning:

"\O" is an invalid escape sequence. Such sequences will not work in the future. Did you mean "\\O"? A raw string is also an option.

<>:3: SyntaxWarning:

"\H" is an invalid escape sequence. Such sequences will not work in the future. Did you mean "\\H"? A raw string is also an option.

<>:4: SyntaxWarning:

"\O" is an invalid escape sequence. Such sequences will not work in the future. Did you mean "\\O"? A raw string is also an option.

<>:5: SyntaxWarning:

"\O" is an invalid escape sequence. Such sequences will not work in the future. Did you mean "\\O"? A raw string is also an option.

<>:7: SyntaxWarning:

"\T" is an invalid escape sequence. Such sequences will not work in the future. Did you mean "\\T"? A raw string is also an option.

<>:8: SyntaxWarning:

"\H" is an invalid escape sequence. Such sequences will not work in the future. Did you mean "\\H"? A raw string is also an option.

<>:9: SyntaxWarning:

"\G" is an invalid escape sequence. Such sequences will not work in the future. Did you mean "\\G"? A raw string is also an option.

<>:10: SyntaxWarning:

"\G" is an invalid escape sequence. Such sequences will not work in the future. Did you mean "\\G"? A raw string is also an option.

C:\Users\Patricia García\AppData\Local\Temp\ipykernel_23584\3925839483.py:2: SyntaxWarning:

"\O" is an invalid escape sequence. Such sequences will not work in the future. Did you mean "\\O"? A raw string is also an option.

C:\Users\Patricia García\AppData\Local\Temp\ipykernel_23584\3925839483.py:3: SyntaxWarning:

"\H" is an invalid escape sequence. Such sequences will not work in the future. Did you mean "\\H"? A raw string is also an option.

C:\Users\Patricia García\AppData\Local\Temp\ipykernel_23584\3925839483.py:4: SyntaxWarning:

"\O" is an invalid escape sequence. Such sequences will not work in the future. Did you mean "\\O"? A raw string is also an option.

C:\Users\Patricia García\AppData\Local\Temp\ipykernel_23584\3925839483.py:5: SyntaxWarning:

"\O" is an invalid escape sequence. Such sequences will not work in the future. Did you mean "\\O"? A raw string is also an option.

C:\Users\Patricia García\AppData\Local\Temp\ipykernel_23584\3925839483.py:7: SyntaxWarning:

"\T" is an invalid escape sequence. Such sequences will not work in the future. Did you mean "\\T"? A raw string is also an option.

C:\Users\Patricia García\AppData\Local\Temp\ipykernel_23584\3925839483.py:8: SyntaxWarning:

"\H" is an invalid escape sequence. Such sequences will not work in the future. Did you mean "\\H"? A raw string is also an option.

C:\Users\Patricia García\AppData\Local\Temp\ipykernel_23584\3925839483.py:9: SyntaxWarning:

"\G" is an invalid escape sequence. Such sequences will not work in the future. Did you mean "\\G"? A raw string is also an option.

C:\Users\Patricia García\AppData\Local\Temp\ipykernel_23584\3925839483.py:10: SyntaxWarning:

"\G" is an invalid escape sequence. Such sequences will not work in the future. Did you mean "\\G"? A raw string is also an option.

In [181]:
# Ver estructura
print("Reservas de Petróleo:")
df_oil_reserves.head()
Reservas de Petróleo:
Out[181]:
Continent Total proved reserves (Bbbl) 2000 2010 2019 2020
0 North America Canada 181,5 174,8 169,1 168,1
1 North America Mexico 24,6 10,4 6,1 6,1
2 North America US 30,4 35,0 68,8 68,8
3 S. & Cent. America Argentina 3,0 2,5 2,5 2,5
4 S. & Cent. America Brazil 8,5 14,2 12,7 11,9

📊 MÓDULO 1: Análisis de Petróleo¶

Recrearemos el gráfico de 3 paneles: Reservas | Producción | Años restantes

1.1 Preparar Datos 2020¶

In [182]:
# Extraer año 2020
oil_2020 = df_oil_reserves[['Continent', df_oil_reserves.columns[1], '2020']].copy()
oil_2020.columns = ['Continente', 'País', 'Reservas_Bbbl']

# Limpiar: formato europeo (181,5) a formato Python (181.5)
oil_2020['Reservas_Bbbl'] = oil_2020['Reservas_Bbbl'].astype(str).str.replace(',', '.')
oil_2020['Reservas_Bbbl'] = pd.to_numeric(oil_2020['Reservas_Bbbl'], errors='coerce')
oil_2020 = oil_2020.dropna(subset=['Reservas_Bbbl'])

print(f"✅ Datos 2020: {len(oil_2020)} países")
print(f"Total mundial: {oil_2020['Reservas_Bbbl'].sum():,.1f} Bbbl")
✅ Datos 2020: 61 países
Total mundial: 6,931.8 Bbbl
In [183]:
# Producción 2020
oil_prod_2020 = df_oil_production[['Continent', df_oil_production.columns[1], '2020']].copy()
oil_prod_2020.columns = ['Continente', 'País', 'Produccion_Mbbl_dia']
oil_prod_2020['Produccion_Mbbl_dia'] = pd.to_numeric(
    oil_prod_2020['Produccion_Mbbl_dia'].astype(str).str.replace(',', '.'), 
    errors='coerce'
)
oil_prod_2020 = oil_prod_2020.dropna()

# Combinar
oil_analysis = oil_2020.merge(oil_prod_2020[['País', 'Produccion_Mbbl_dia']], on='País')

print(f"✅ {len(oil_analysis)} países con ambos datos")
✅ 58 países con ambos datos
In [184]:
# PASO 3: Combinar reservas y producción (como ya lo tienes)
oil_analysis = oil_2020.merge(
    oil_prod_2020[['País', 'Produccion_Mbbl_dia']], 
    on='País', 
    how='inner'
)

print(f"Datos combinados: {len(oil_analysis)} registros iniciales")

# PASO 4: FILTRAR AGREGACIONES (NUEVO - AGREGAR AQUÍ)
# Lista de términos que indican totales o agrupaciones
aggregations_to_exclude = [
    'World', 'OPEC', 'Non-OPEC', 'OECD', 'Non-OECD', 
    'Total', 'of which', 'Other', 'Europe', 'European Union', 'EU',
    'Asia', 'Africa', 'Middle East', 'CIS', 'S. & Cent. America'
]

exclusion_pattern = '|'.join(aggregations_to_exclude)

oil_analysis = oil_analysis[~oil_analysis['País'].str.contains(
    exclusion_pattern, 
    case=False,
    na=False
)]

print(f"✅ Después de filtrar agregaciones: {len(oil_analysis)} países reales")

# PASO 5: Calcular producción anual (continúa como antes)
oil_analysis['Produccion_Anual_Mbbl'] = oil_analysis['Produccion_Mbbl_dia'] * 365 / 1000

# PASO 6: Calcular R/P Ratio (continúa como antes)
oil_analysis['RP_Ratio_Years'] = (oil_analysis['Reservas_Bbbl'] * 1000) / oil_analysis['Produccion_Anual_Mbbl']
oil_analysis['RP_Ratio_Years'] = oil_analysis['RP_Ratio_Years'].replace([np.inf, -np.inf], np.nan)

print("✅ R/P Ratio calculado")

# PASO 7: Ahora sí, seleccionar Top 15 PAÍSES REALES
top15_oil = oil_analysis.nlargest(15, 'Reservas_Bbbl').sort_values('Reservas_Bbbl')

print("\n🏆 Top 15 Países por Reservas (verificación):")
for idx, row in top15_oil.iterrows():
    print(f"   {row['País']}: {row['Reservas_Bbbl']:.1f} Bbbl")
Datos combinados: 58 registros iniciales
✅ Después de filtrar agregaciones: 49 países reales
✅ R/P Ratio calculado

🏆 Top 15 Países por Reservas (verificación):
   Algeria: 12.2 Bbbl
   Qatar: 25.2 Bbbl
   China: 26.0 Bbbl
   Kazakhstan: 30.0 Bbbl
   Nigeria: 36.9 Bbbl
   Libya: 48.4 Bbbl
   US: 68.8 Bbbl
   United Arab Emirates: 97.8 Bbbl
   Kuwait: 101.5 Bbbl
   Russian Federation: 107.8 Bbbl
   Iraq: 145.0 Bbbl
   Iran: 157.8 Bbbl
   Canada: 168.1 Bbbl
   Saudi Arabia: 297.5 Bbbl
   Venezuela: 303.8 Bbbl

1.2 Calcular R/P Ratio¶

El R/P Ratio indica cuántos años durarán las reservas. Fórmula: Reservas / Producción Anual

Necesitamos convertir unidades: Reservas en Bbbl (miles de millones) y Producción en Mbbl/día.

In [185]:
# Producción anual = diaria × 365 días ÷ 1000 (para convertir a millones)
oil_analysis['Produccion_Anual_Mbbl'] = oil_analysis['Produccion_Mbbl_dia'] * 365 / 1000

# R/P Ratio = (Reservas en billions × 1000) / Producción en millions
oil_analysis['RP_Ratio_Years'] = (oil_analysis['Reservas_Bbbl'] * 1000) / oil_analysis['Produccion_Anual_Mbbl']
oil_analysis['RP_Ratio_Years'] = oil_analysis['RP_Ratio_Years'].replace([np.inf, -np.inf], np.nan)

print("✅ R/P Ratio calculado")
print("\nTop 5 con más años:")
top_rp = oil_analysis.nlargest(5, 'RP_Ratio_Years')[['País', 'RP_Ratio_Years']]
for _, row in top_rp.iterrows():
    print(f"   {row['País']}: {row['RP_Ratio_Years']:.0f} años")
✅ R/P Ratio calculado

Top 5 con más años:
   Venezuela: 1231 años
   Libya: 313 años
   Syria: 159 años
   Iran: 134 años
   Kuwait: 102 años

1.3 Gráfico Analytics (3 Paneles)¶

Usaremos make_subplots para crear 3 gráficos lado a lado.

In [186]:
# Top 15 países
top15_oil = oil_analysis.nlargest(15, 'Reservas_Bbbl').sort_values('Reservas_Bbbl')

# Crear figura con 3 columnas
fig = make_subplots(
    rows=1, cols=3,
    subplot_titles=(
        'Reservas Probadas<br><sub>(Bbbl)</sub>',
        'Producción<br><sub>(Mbbl/día)</sub>',
        '¿Cuánto Durará?<br><sub>(Años)</sub>'
    ),
    column_widths=[0.3, 0.3, 0.4],
    horizontal_spacing=0.08
)

# Panel 1: Reservas (barras azules)
fig.add_trace(go.Bar(
    y=top15_oil['País'],
    x=top15_oil['Reservas_Bbbl'],
    orientation='h',
    marker_color='rgb(55, 125, 184)',
    showlegend=False,
    text=top15_oil['Reservas_Bbbl'].round(1),
    textposition='outside'
), row=1, col=1)

# Panel 2: Producción (barras rojas)
fig.add_trace(go.Bar(
    y=top15_oil['País'],
    x=top15_oil['Produccion_Mbbl_dia'],
    orientation='h',
    marker_color='rgb(228, 87, 86)',
    showlegend=False,
    text=top15_oil['Produccion_Mbbl_dia'].round(0),
    textposition='outside'
), row=1, col=2)

# Panel 3: R/P Ratio (puntos con líneas)
fig.add_trace(go.Scatter(
    y=top15_oil['País'],
    x=top15_oil['RP_Ratio_Years'],
    mode='lines+markers',
    marker=dict(size=10, color='rgb(55, 125, 184)', line=dict(width=2, color='white')),
    line=dict(width=2, color='rgb(55, 125, 184)'),
    showlegend=False,
    text=top15_oil['RP_Ratio_Years'].round(0).astype(str) + 'Y',
    textposition='middle right'
), row=1, col=3)

# Diseño
fig.update_layout(
    title='🛢️ Top 15 Países - Reservas de Petróleo (2020)',
    height=700,
    plot_bgcolor='white'
)
fig.update_xaxes(showgrid=True, gridcolor='lightgray')
fig.update_yaxes(showgrid=False, row=1, col=1)
fig.update_yaxes(showticklabels=False, row=1, col=2)
fig.update_yaxes(showticklabels=False, row=1, col=3)

fig.show()

Interpretación: Venezuela lidera en reservas pero USA produce más. El R/P muestra que Venezuela tiene petróleo para 1000+ años mientras USA solo 7 años al ritmo actual.

In [187]:
# ============================================================================
# GRÁFICO DE DISPERSIÓN: Petróleo vs Gas con Venezuela Destacada
# ============================================================================
print("\n🎨 Creando gráfico de dispersión bidimensional...")

# Usar comparison_df que ya tiene ambos tipos de reservas
scatter_data = comparison_df.copy()

# Crear una columna que identifique a Venezuela
scatter_data['Tipo'] = scatter_data['País'].apply(
    lambda x: '🇻🇪 VENEZUELA' if x == 'Venezuela' else 'Otros países'
)

# Crear tamaños de puntos (Venezuela más grande)
scatter_data['Tamaño'] = scatter_data['País'].apply(
    lambda x: 30 if x == 'Venezuela' else 15
)

# Crear el gráfico de dispersión
fig_scatter_vzla = px.scatter(
    scatter_data,
    x='Reservas_Bbbl',
    y='Reservas_Tcm',
    color='Tipo',
    size='Tamaño',
    text='País',
    title='💎 Perfil Energético: Reservas de Petróleo vs Gas Natural<br>' +
          '<sub>Venezuela destacada - Posición única en el panorama global</sub>',
    labels={
        'Reservas_Bbbl': 'Reservas de Petróleo (Bbbl)',
        'Reservas_Tcm': 'Reservas de Gas Natural (Tcm)'
    },
    color_discrete_map={
        '🇻🇪 VENEZUELA': 'rgb(255, 193, 7)',  # Dorado
        'Otros países': 'rgb(100, 100, 100)'   # Gris
    },
    hover_data={
        'Reservas_Bbbl': ':.1f',
        'Reservas_Tcm': ':.1f',
        'Tipo': False,
        'Tamaño': False
    }
)

# Personalizar las etiquetas de los puntos
fig_scatter_vzla.update_traces(
    textposition='top center',
    textfont=dict(size=10),
    marker=dict(
        line=dict(width=2, color='white')
    )
)

# Personalizar diseño
fig_scatter_vzla.update_layout(
    height=700,
    plot_bgcolor='white',
    xaxis=dict(
        showgrid=True,
        gridcolor='lightgray',
        zeroline=False
    ),
    yaxis=dict(
        showgrid=True,
        gridcolor='lightgray',
        zeroline=False
    ),
    legend=dict(
        title='',
        yanchor='top',
        y=0.99,
        xanchor='left',
        x=0.01,
        font=dict(size=14)
    )
)

# Añadir líneas de referencia marcando los valores de Venezuela
if len(venezuela_data) > 0:
    # Línea vertical en el valor de petróleo de Venezuela
    fig_scatter_vzla.add_vline(
        x=venezuela_oil,
        line_dash="dash",
        line_color="orange",
        opacity=0.5,
        annotation_text=f"Petróleo VEN<br>{venezuela_oil:.0f} Bbbl",
        annotation_position="top"
    )
    
    # Línea horizontal en el valor de gas de Venezuela
    fig_scatter_vzla.add_hline(
        y=venezuela_gas,
        line_dash="dash",
        line_color="orange",
        opacity=0.5,
        annotation_text=f"Gas VEN: {venezuela_gas:.0f} Tcm",
        annotation_position="right"
    )

print("✅ Gráfico de dispersión creado")
print("\n💡 CÓMO INTERPRETAR ESTE GRÁFICO:")
print("   • Eje X (horizontal) = Reservas de PETRÓLEO")
print("   • Eje Y (vertical) = Reservas de GAS")
print("   • Venezuela está en DORADO y más GRANDE que los demás")
print("   • Las líneas punteadas naranjas marcan los niveles de Venezuela")
print("\n🔍 CUADRANTES DEL GRÁFICO:")
print("   • Superior Derecha = Mucho petróleo Y mucho gas (gigantes totales)")
print("   • Inferior Derecha = Mucho petróleo, poco gas (Venezuela está aquí)")
print("   • Superior Izquierda = Poco petróleo, mucho gas (Rusia está aquí)")
print("   • Inferior Izquierda = Poco de ambos (productores menores)")
print("\n🎯 LO QUE REVELA:")
print("   • La posición ÚNICA de Venezuela en el panorama energético")
print("   • Qué países tienen perfiles similares o complementarios")
print("   • La especialización de cada país en petróleo vs gas")

fig_scatter_vzla.show()
🎨 Creando gráfico de dispersión bidimensional...
✅ Gráfico de dispersión creado

💡 CÓMO INTERPRETAR ESTE GRÁFICO:
   • Eje X (horizontal) = Reservas de PETRÓLEO
   • Eje Y (vertical) = Reservas de GAS
   • Venezuela está en DORADO y más GRANDE que los demás
   • Las líneas punteadas naranjas marcan los niveles de Venezuela

🔍 CUADRANTES DEL GRÁFICO:
   • Superior Derecha = Mucho petróleo Y mucho gas (gigantes totales)
   • Inferior Derecha = Mucho petróleo, poco gas (Venezuela está aquí)
   • Superior Izquierda = Poco petróleo, mucho gas (Rusia está aquí)
   • Inferior Izquierda = Poco de ambos (productores menores)

🎯 LO QUE REVELA:
   • La posición ÚNICA de Venezuela en el panorama energético
   • Qué países tienen perfiles similares o complementarios
   • La especialización de cada país en petróleo vs gas
In [188]:
# ============================================================================
# GRÁFICOS PARALELOS: Petróleo y Gas con Venezuela Destacada
# ============================================================================
print("\n🎨 Creando gráficos paralelos comparativos...")

# Crear figura con dos columnas
fig_parallel = make_subplots(
    rows=1, cols=2,
    subplot_titles=(
        '🛢️ RESERVAS DE PETRÓLEO<br><sub>(Thousand million barrels)</sub>',
        '🔥 RESERVAS DE GAS NATURAL<br><sub>(Trillion cubic meters)</sub>'
    ),
    horizontal_spacing=0.15
)

# Ordenar datos para petróleo (de mayor a menor)
oil_sorted = comparison_df.sort_values('Reservas_Bbbl', ascending=True)

# Crear colores: Venezuela en dorado, otros en azul
colors_oil = [
    'rgb(255, 193, 7)' if pais == 'Venezuela' else 'rgb(55, 125, 184)'
    for pais in oil_sorted['País']
]

# Panel 1: Petróleo
fig_parallel.add_trace(
    go.Bar(
        y=oil_sorted['País'],
        x=oil_sorted['Reservas_Bbbl'],
        orientation='h',
        marker_color=colors_oil,
        marker_line_color=[
            'rgb(255, 87, 34)' if pais == 'Venezuela' else 'rgba(0,0,0,0)'
            for pais in oil_sorted['País']
        ],
        marker_line_width=[3 if pais == 'Venezuela' else 0 for pais in oil_sorted['País']],
        text=oil_sorted['Reservas_Bbbl'].round(1),
        textposition='outside',
        textfont=dict(
            size=[12 if pais == 'Venezuela' else 10 for pais in oil_sorted['País']],
            color=[
                'rgb(255, 87, 34)' if pais == 'Venezuela' else 'black'
                for pais in oil_sorted['País']
            ]
        ),
        hovertemplate='<b>%{y}</b><br>Petróleo: %{x:.1f} Bbbl<extra></extra>',
        showlegend=False
    ),
    row=1, col=1
)

# Ordenar datos para gas (de mayor a menor)
gas_sorted = comparison_df.sort_values('Reservas_Tcm', ascending=True)

# Crear colores para gas
colors_gas = [
    'rgb(255, 193, 7)' if pais == 'Venezuela' else 'rgb(76, 175, 80)'
    for pais in gas_sorted['País']
]

# Panel 2: Gas
fig_parallel.add_trace(
    go.Bar(
        y=gas_sorted['País'],
        x=gas_sorted['Reservas_Tcm'],
        orientation='h',
        marker_color=colors_gas,
        marker_line_color=[
            'rgb(255, 87, 34)' if pais == 'Venezuela' else 'rgba(0,0,0,0)'
            for pais in gas_sorted['País']
        ],
        marker_line_width=[3 if pais == 'Venezuela' else 0 for pais in gas_sorted['País']],
        text=gas_sorted['Reservas_Tcm'].round(1),
        textposition='outside',
        textfont=dict(
            size=[12 if pais == 'Venezuela' else 10 for pais in gas_sorted['País']],
            color=[
                'rgb(255, 87, 34)' if pais == 'Venezuela' else 'black'
                for pais in gas_sorted['País']
            ]
        ),
        hovertemplate='<b>%{y}</b><br>Gas Natural: %{x:.1f} Tcm<extra></extra>',
        showlegend=False
    ),
    row=1, col=2
)

# Configurar diseño
fig_parallel.update_layout(
    title=dict(
        text='🇻🇪 VENEZUELA en Contexto Global: Domina en Petróleo vs Posición en Gas<br>' +
             '<sub>Venezuela | Comparación con principales productores</sub>',
        font=dict(size=14),
        x=0.5,
        xanchor='center'
    ),
    height=700,
    showlegend=False,
    plot_bgcolor='white'
)

# Personalizar ejes
fig_parallel.update_xaxes(showgrid=True, gridcolor='lightgray', row=1, col=1)
fig_parallel.update_xaxes(showgrid=True, gridcolor='lightgray', row=1, col=2)
fig_parallel.update_yaxes(showgrid=False, row=1, col=1)
fig_parallel.update_yaxes(showgrid=False, row=1, col=2)

print("✅ Gráficos paralelos creados")
print("\n💡 INTERPRETACIÓN:")
print("==================================================")
print("   • IZQUIERDA = Ranking de PETRÓLEO (Venezuela domina)")
print("   • DERECHA = Ranking de GAS NATURAL (otros países destacan)")
print("==================================================")
print("   • Venezuela en DORADO con borde naranja en ambos gráficos")
print("==================================================")
print("\n🔍 COMPARA:")
print("==================================================")
print("   • Posición de Venezuela en ambos rankings")
print("==================================================")
print("   • Qué países cambian de posición entre petróleo y gas")
print("   • La brecha entre Venezuela y el #2 en cada recurso")

fig_parallel.show()
🎨 Creando gráficos paralelos comparativos...
✅ Gráficos paralelos creados

💡 INTERPRETACIÓN:
==================================================
   • IZQUIERDA = Ranking de PETRÓLEO (Venezuela domina)
   • DERECHA = Ranking de GAS NATURAL (otros países destacan)
==================================================
   • Venezuela en DORADO con borde naranja en ambos gráficos
==================================================

🔍 COMPARA:
==================================================
   • Posición de Venezuela en ambos rankings
==================================================
   • Qué países cambian de posición entre petróleo y gas
   • La brecha entre Venezuela y el #2 en cada recurso
In [189]:
# ============================================================================
# GRÁFICO DE BURBUJAS: Reservas vs Producción vs R/P Ratio
# ============================================================================
# Este gráfico muestra las 3 variables clave en una sola visualización
# X = Reservas, Y = Producción, Tamaño = R/P Ratio

print("🎨 Creando gráfico de burbujas...")

# Filtrar datos para tener solo valores válidos (sin NaN en R/P Ratio)
bubble_data = oil_analysis.dropna(subset=['RP_Ratio_Years']).copy()

# Para que el gráfico no se vea saturado, tomemos Top 30 países por reservas
# También podríamos tomar todos los países, pero 30 es un buen balance
top30_bubble = bubble_data.nlargest(30, 'Reservas_Bbbl')

# Crear el gráfico de burbujas usando plotly express
# px.scatter() con el parámetro size crea un gráfico de burbujas
fig_bubble = px.scatter(
    top30_bubble,
    x='Reservas_Bbbl',  # Eje horizontal: Reservas
    y='Produccion_Mbbl_dia',  # Eje vertical: Producción diaria
    size='RP_Ratio_Years',  # Tamaño de burbuja: Cuántos años durarán
    color='Continente',  # Color por continente para ver patrones regionales
    hover_name='País',  # Mostrar nombre del país al pasar el mouse
    hover_data={  # Datos adicionales en el tooltip
        'Reservas_Bbbl': ':.1f',
        'Produccion_Mbbl_dia': ':.0f',
        'RP_Ratio_Years': ':.0f años',
        'Continente': True
    },
    size_max=60,  # Tamaño máximo de las burbujas (para que no se vean gigantes)
    title='💎 Análisis Multidimensional: Reservas, Producción y Duración<br>' +
          '<sub>Tamaño de burbuja = Años restantes (R/P Ratio)</sub>',
    labels={
        'Reservas_Bbbl': 'Reservas Probadas (Bbbl)',
        'Produccion_Mbbl_dia': 'Producción Diaria (Mbbl/día)',
        'Continente': 'Región'
    }
)

# Personalizar el diseño
fig_bubble.update_layout(
    height=700,
    plot_bgcolor='white',
    xaxis=dict(
        showgrid=True, 
        gridcolor='lightgray',
        zeroline=False
    ),
    yaxis=dict(
        showgrid=True, 
        gridcolor='lightgray',
        zeroline=False
    ),
    legend=dict(
        title='Región',
        yanchor='top',
        y=0.99,
        xanchor='left',
        x=0.01
    )
)

# Añadir líneas de referencia opcionales
# Por ejemplo, una línea diagonal imaginaria que representa "uso eficiente"
# Países por encima de esta línea producen mucho comparado con sus reservas
# Países por debajo son más conservadores

print("✅ Gráfico de burbujas creado")
print("\n💡 CÓMO INTERPRETAR:")
print("   • Eje X (horizontal) = Cuántas reservas tiene el país")
print("   • Eje Y (vertical) = Cuánto produce diariamente")
print("   • Tamaño de círculo = Cuántos años le durarán las reservas")
print("   • Color = Región geográfica")
print("\n🔍 BUSCA PATRONES:")
print("   • Burbujas GRANDES = Reservas duraderas (producción conservadora)")
print("   • Burbujas PEQUEÑAS = Reservas se agotan rápido (producción agresiva)")
print("   • Esquina SUPERIOR DERECHA = Gigantes (muchas reservas Y mucha producción)")
print("   • Esquina INFERIOR IZQUIERDA = Productores menores")

fig_bubble.show()
🎨 Creando gráfico de burbujas...
✅ Gráfico de burbujas creado

💡 CÓMO INTERPRETAR:
   • Eje X (horizontal) = Cuántas reservas tiene el país
   • Eje Y (vertical) = Cuánto produce diariamente
   • Tamaño de círculo = Cuántos años le durarán las reservas
   • Color = Región geográfica

🔍 BUSCA PATRONES:
   • Burbujas GRANDES = Reservas duraderas (producción conservadora)
   • Burbujas PEQUEÑAS = Reservas se agotan rápido (producción agresiva)
   • Esquina SUPERIOR DERECHA = Gigantes (muchas reservas Y mucha producción)
   • Esquina INFERIOR IZQUIERDA = Productores menores
In [190]:
# ============================================================================
# TREEMAP: Proporción de Reservas Mundiales por País
# ============================================================================
# Muestra qué porcentaje del total mundial tiene cada país
# El tamaño de cada rectángulo es proporcional a las reservas

print("🎨 Creando Treemap de distribución mundial...")

# Tomar Top 20 países por reservas para que el treemap sea legible
# Si incluimos todos los países, los más pequeños serían invisibles
top20_treemap = oil_analysis.nlargest(20, 'Reservas_Bbbl').copy()

# Calcular el porcentaje que cada país representa del total mundial
total_mundial = oil_analysis['Reservas_Bbbl'].sum()
top20_treemap['Porcentaje_Mundial'] = (
    top20_treemap['Reservas_Bbbl'] / total_mundial * 100
).round(2)

# Crear etiquetas informativas para cada rectángulo
# Incluiremos el país, las reservas y el porcentaje
top20_treemap['Etiqueta'] = top20_treemap.apply(
    lambda row: f"{row['País']}<br>{row['Reservas_Bbbl']:.1f} Bbbl<br>({row['Porcentaje_Mundial']:.1f}%)",
    axis=1
)

# Crear el treemap usando plotly express
fig_treemap = px.treemap(
    top20_treemap,
    path=[px.Constant("🌍 Reservas Mundiales"), 'Continente', 'País'],  # Jerarquía
    values='Reservas_Bbbl',  # El tamaño de cada rectángulo
    color='Continente',  # Color por región
    hover_data={
        'Reservas_Bbbl': ':.1f',
        'Porcentaje_Mundial': ':.2f%',
        'Continente': True
    },
    title='🗺️ Distribución Global de Reservas de Petróleo<br>' +
          '<sub>Top 20 países - Tamaño proporcional a reservas probadas</sub>'
)

# Personalizar el diseño
fig_treemap.update_layout(
    height=700,
    font=dict(size=12)
)

# Personalizar las etiquetas dentro de los rectángulos
fig_treemap.update_traces(
    textposition='middle center',
    textfont=dict(size=11, color='white'),
    marker=dict(line=dict(color='white', width=2))  # Borde blanco entre rectángulos
)

print("✅ Treemap creado")
print("\n💡 CÓMO INTERPRETAR:")
print("   • Cada rectángulo = Un país")
print("   • TAMAÑO del rectángulo = Proporción de reservas mundiales")
print("   • COLOR = Región geográfica")
print("   • Rectángulos grandes = Países que controlan gran % del total")
print("\n🔍 OBSERVA:")
print("   • ¿Cuántos países necesitas sumar para llegar al 50% mundial?")
print("   • ¿Qué región geográfica domina el mapa?")
print("   • ¿Hay concentración (pocos países grandes) o distribución?")

fig_treemap.show()
🎨 Creando Treemap de distribución mundial...
✅ Treemap creado

💡 CÓMO INTERPRETAR:
   • Cada rectángulo = Un país
   • TAMAÑO del rectángulo = Proporción de reservas mundiales
   • COLOR = Región geográfica
   • Rectángulos grandes = Países que controlan gran % del total

🔍 OBSERVA:
   • ¿Cuántos países necesitas sumar para llegar al 50% mundial?
   • ¿Qué región geográfica domina el mapa?
   • ¿Hay concentración (pocos países grandes) o distribución?
In [191]:
# ============================================================================
# GRÁFICO DE BARRAS APILADAS: Composición Regional de Reservas
# ============================================================================
# Muestra cómo se distribuyen las reservas DENTRO de cada región

print("🎨 Creando gráfico de composición regional...")

# Agrupar datos por continente y país
regional_data = oil_analysis.copy()

# Para cada continente, calcular qué porcentaje representa cada país
regional_data['Total_Regional'] = regional_data.groupby('Continente')['Reservas_Bbbl'].transform('sum')
regional_data['Porcentaje_Regional'] = (
    regional_data['Reservas_Bbbl'] / regional_data['Total_Regional'] * 100
)

# Filtrar para tomar solo los países más significativos de cada región
# Tomemos países que representen al menos 5% de su región
significant_countries = regional_data[regional_data['Porcentaje_Regional'] >= 5].copy()

# Si una región tiene muchos países pequeños, podemos agruparlos como "Otros"
# Esto lo haremos manualmente por región si es necesario

# Crear el gráfico de barras apiladas
fig_stacked = px.bar(
    significant_countries,
    x='Continente',
    y='Reservas_Bbbl',
    color='País',
    title='🌍 Composición de Reservas por Región<br>' +
          '<sub>Distribución interna de cada continente</sub>',
    labels={
        'Reservas_Bbbl': 'Reservas Probadas (Bbbl)',
        'Continente': 'Región'
    },
    hover_data={
        'Reservas_Bbbl': ':.1f',
        'Porcentaje_Regional': ':.1f%'
    }
)

# Personalizar para que sea un gráfico apilado al 100%
fig_stacked.update_layout(
    barmode='stack',
    height=600,
    xaxis_title='Región',
    yaxis_title='Reservas Totales (Bbbl)',
    plot_bgcolor='white',
    legend=dict(
        title='País',
        orientation='v',
        yanchor='top',
        y=1,
        xanchor='left',
        x=1.02
    )
)

print("✅ Gráfico de composición regional creado")
print("\n💡 INTERPRETACIÓN:")
print("   • Cada barra = Una región del mundo")
print("   • ALTURA total = Reservas totales de esa región")
print("   • Segmentos de COLOR = Países dentro de esa región")
print("   • Tamaño del segmento = Contribución al total regional")
print("\n🔍 PREGÚNTATE:")
print("   • ¿Qué regiones tienen concentración (1-2 países dominan)?")
print("   • ¿Qué regiones tienen distribución más equilibrada?")
print("   • ¿Qué región tiene las mayores reservas absolutas?")

fig_stacked.show()
🎨 Creando gráfico de composición regional...
✅ Gráfico de composición regional creado

💡 INTERPRETACIÓN:
   • Cada barra = Una región del mundo
   • ALTURA total = Reservas totales de esa región
   • Segmentos de COLOR = Países dentro de esa región
   • Tamaño del segmento = Contribución al total regional

🔍 PREGÚNTATE:
   • ¿Qué regiones tienen concentración (1-2 países dominan)?
   • ¿Qué regiones tienen distribución más equilibrada?
   • ¿Qué región tiene las mayores reservas absolutas?

1.4 Mapa Mundial de Reservas¶

Vamos a crear un mapa coroplético donde cada país se colorea según sus reservas.

¿Cómo funciona? Plotly tiene una función llamada choropleth que toma el nombre de los países y un valor numérico (las reservas). Automáticamente encuentra la ubicación geográfica de cada país y lo colorea en un gradiente: amarillo para reservas bajas, naranja para medias, y rojo para altas.

In [192]:
# Preparar nombres de países para el mapa
# Algunos nombres necesitan ajustarse para que Plotly los reconozca

country_mapping = {
    'US': 'United States',
    'UK': 'United Kingdom',
    'UAE': 'United Arab Emirates'
}

oil_analysis['País_Mapa'] = oil_analysis['País'].replace(country_mapping)

# Crear mapa coroplético
# px.choropleth() es la función que crea mapas donde países se colorean por valores

fig_map = px.choropleth(
    oil_analysis,  # Nuestros datos
    locations='País_Mapa',  # Columna con nombres de países
    locationmode='country names',  # Decimos que use nombres, no códigos
    color='Reservas_Bbbl',  # Esta columna determina el color
    hover_name='País',  # Qué mostrar al pasar el mouse
    hover_data={  # Datos adicionales al pasar mouse
        'Reservas_Bbbl': ':,.1f',  # Formato con decimales
        'Produccion_Mbbl_dia': ':,.0f',
        'RP_Ratio_Years': ':,.0f',
        'País_Mapa': False  # No mostrar esta columna técnica
    },
    color_continuous_scale='YlOrRd',  # Escala: Yellow-Orange-Red
    labels={  # Etiquetas en español
        'Reservas_Bbbl': 'Reservas (Bbbl)',
        'Produccion_Mbbl_dia': 'Producción (Mbbl/día)',
        'RP_Ratio_Years': 'Años restantes'
    },
    title='🗺️ Reservas Probadas de Petróleo por País (2020)'
)

# Personalizar el mapa
fig_map.update_layout(
    geo=dict(
        showframe=False,  # Sin marco alrededor
        showcoastlines=True,  # Mostrar líneas costeras
        projection_type='natural earth',  # Proyección del mapa
        bgcolor='lightblue'  # Color de los océanos
    ),
    height=600,
    title_font_size=18
)

print("✅ Mapa creado")
print("💡 Puedes hacer zoom con la rueda del mouse")
print("💡 Arrastra para mover el mapa")

fig_map.show()
✅ Mapa creado
💡 Puedes hacer zoom con la rueda del mouse
💡 Arrastra para mover el mapa
C:\Users\Patricia García\AppData\Local\Temp\ipykernel_23584\2073054508.py:15: DeprecationWarning:

The library used by the *country names* `locationmode` option is changing in an upcoming version. Country names in existing plots may not work in the new version. To ensure consistent behavior, consider setting `locationmode` to *ISO-3*.

1.5 Evolución de Reservas (1980-2020)¶

Ahora veremos cómo han cambiado las reservas a lo largo de 40 años. Usaremos un gráfico de líneas donde cada país tendrá su propia línea de color.

¿Por qué 40 años? Este período nos permite ver cambios significativos: descubrimientos de nuevos yacimientos, mejoras tecnológicas que reclasifican reservas, y el impacto de la producción acumulada.

In [193]:
# Seleccionar Top 10 países por reservas actuales
top10_countries = oil_analysis.nlargest(10, 'Reservas_Bbbl')['País'].tolist()

print("📊 Top 10 países para análisis temporal:")
for i, country in enumerate(top10_countries, 1):
    print(f"   {i}. {country}")

# Filtrar datos históricos solo para estos países
country_col = df_oil_reserves_history.columns[1]  # Segunda columna tiene nombres
df_history_top10 = df_oil_reserves_history[
    df_oil_reserves_history[country_col].isin(top10_countries)
].copy()

# Identificar columnas de años (son las que tienen solo números)
year_columns = [col for col in df_history_top10.columns if col.isdigit()]

# Transformar de formato "ancho" a "largo"
# Formato ancho: una columna por año (1980, 1981, 1982...)
# Formato largo: una columna "Año" y una columna "Valor"
# ¿Por qué? Plotly prefiere formato largo para gráficos de líneas

df_melted = df_history_top10.melt(
    id_vars=[country_col],  # Columnas que NO transformamos
    value_vars=year_columns,  # Columnas que SÍ transformamos
    var_name='Año',  # Nombre de la nueva columna de años
    value_name='Reservas'  # Nombre de la nueva columna de valores
)

df_melted = df_melted.rename(columns={country_col: 'País'})

# Limpiar datos
df_melted['Año'] = pd.to_numeric(df_melted['Año'], errors='coerce')
df_melted['Reservas'] = df_melted['Reservas'].astype(str).str.replace(',', '.')
df_melted['Reservas'] = pd.to_numeric(df_melted['Reservas'], errors='coerce')
df_melted = df_melted.dropna()

print(f"✅ Datos preparados: {len(df_melted)} registros")
print(f"   Años: {df_melted['Año'].min():.0f} - {df_melted['Año'].max():.0f}")
📊 Top 10 países para análisis temporal:
   1. Venezuela
   2. Saudi Arabia
   3. Canada
   4. Iran
   5. Iraq
   6. Russian Federation
   7. Kuwait
   8. United Arab Emirates
   9. US
   10. Libya
✅ Datos preparados: 399 registros
   Años: 1980 - 2020
In [194]:
# Crear gráfico de líneas temporal
# px.line() crea gráficos perfectos para mostrar evolución en el tiempo

fig_temporal = px.line(
    df_melted,
    x='Año',
    y='Reservas',
    color='País',  # Cada país tiene su color
    markers=True,  # Añadir puntos en cada año
    title='📈 Evolución de Reservas de Petróleo (1980-2020)<br><sub>Top 10 Países</sub>',
    labels={'Reservas': 'Reservas Probadas (Bbbl)', 'Año': 'Año'},
    color_discrete_sequence=px.colors.qualitative.Set1  # Colores distintivos
)

# Personalizar
fig_temporal.update_layout(
    height=600,
    hovermode='x unified',  # Mostrar todos los países al pasar mouse
    legend=dict(title='País', yanchor='top', y=1, xanchor='left', x=1.02),
    xaxis=dict(showgrid=True, gridcolor='lightgray'),
    yaxis=dict(showgrid=True, gridcolor='lightgray'),
    plot_bgcolor='white'
)

print("✅ Gráfico temporal creado")
print("💡 Haz clic en países en la leyenda para mostrar/ocultar")
print("💡 Doble clic en un país para ver solo ese")

fig_temporal.show()
✅ Gráfico temporal creado
💡 Haz clic en países en la leyenda para mostrar/ocultar
💡 Doble clic en un país para ver solo ese

💡 Hallazgos del Análisis Temporal¶

Observa estos patrones importantes en el gráfico:

Venezuela - El Gran Salto (1998-1999): Las reservas venezolanas se multiplicaron casi por 8 en solo un año. Esto no fue porque descubrieron petróleo nuevo de repente, sino porque reclasificaron el petróleo extra-pesado de la Faja del Orinoco como "probado" gracias a avances tecnológicos que demostraron que era económicamente viable extraerlo.

Canadá - Crecimiento Sostenido: Las reservas canadienses crecieron significativamente desde el año 2000. La razón es similar a Venezuela: las arenas bituminosas de Alberta fueron reclasificadas como reservas probadas cuando la tecnología y los precios del petróleo hicieron rentable su extracción.

Arabia Saudita e Irán: Mantienen reservas relativamente estables a lo largo de las décadas. Esto no significa que no produzcan petróleo, sino que constantemente están descubriendo y reclasificando nuevas reservas que compensan lo que extraen.

Estados Unidos - Resurgimiento Reciente: Después de décadas de declive, las reservas estadounidenses aumentaron dramáticamente desde 2010. Esto se debe al boom del fracking (fracturación hidráulica) y la explotación del shale oil (petróleo de esquisto) que revolucionó la industria.

México - Declive Continuo: Las reservas mexicanas han disminuido consistentemente desde 1980. Esto refleja que sus principales campos petroleros (como Cantarell) son maduros y están en declive, y no se han encontrado suficientes nuevas reservas para compensar.


📊 MÓDULO 2: Análisis de Gas Natural¶

El gas natural es otro recurso energético crucial. Muchos países tienen proporciones muy diferentes de petróleo versus gas en sus reservas. Por ejemplo, Rusia tiene muchísimo más gas que petróleo, mientras que Venezuela es al revés.

Aplicaremos el mismo análisis que hicimos con petróleo: gráfico de 3 paneles, mapa mundial, y análisis temporal.

2.1 Preparar Datos de Gas¶

In [195]:
# Extraer año 2020 de gas
# Las unidades son Tcm (Trillion cubic meters = billones de metros cúbicos)

gas_2020 = df_gas_reserves[['Continent', df_gas_reserves.columns[1], '2020']].copy()
gas_2020.columns = ['Continente', 'País', 'Reservas_Tcm']

# Limpiar datos de reservas
# Convertimos las comas europeas a puntos para que Python entienda los decimales
gas_2020['Reservas_Tcm'] = gas_2020['Reservas_Tcm'].astype(str).str.replace(',', '.')
gas_2020['Reservas_Tcm'] = pd.to_numeric(gas_2020['Reservas_Tcm'], errors='coerce')
gas_2020 = gas_2020.dropna()

print(f"Reservas de gas cargadas: {len(gas_2020)} registros iniciales")

# Producción de gas (encontrar año más reciente disponible en los datos)
year_cols_gas = [col for col in df_gas_production.columns if col.isdigit()]
latest_year = max(year_cols_gas, key=lambda x: int(x))

print(f"Usando datos de producción del año: {latest_year}")

gas_prod = df_gas_production[['Continent', df_gas_production.columns[1], latest_year]].copy()
gas_prod.columns = ['Continente', 'País', 'Produccion_Bcm']

# Limpiar datos de producción
gas_prod['Produccion_Bcm'] = gas_prod['Produccion_Bcm'].astype(str).str.replace(',', '.')
gas_prod['Produccion_Bcm'] = pd.to_numeric(gas_prod['Produccion_Bcm'], errors='coerce')
gas_prod = gas_prod.dropna()

print(f"Producción de gas cargada: {len(gas_prod)} registros")

# Combinar reservas y producción
# El merge une las dos tablas por la columna 'País'
gas_analysis = gas_2020.merge(gas_prod[['País', 'Produccion_Bcm']], on='País')

print(f"Datos combinados: {len(gas_analysis)} registros antes de filtrar")

# ============================================================================
# NUEVO: FILTRAR AGREGACIONES Y TOTALES
# ============================================================================
# Este es el paso crítico donde eliminamos las filas que no representan países
# individuales sino totales o agrupaciones

# La misma lista de términos que usamos para petróleo
# Estos identifican filas que son sumas, totales o bloques regionales
aggregations_to_exclude = [
    'World',           # Total mundial
    'OPEC',            # Organización de Países Exportadores de Petróleo
    'Non-OPEC',        # Países que no son OPEC
    'OECD',            # Organización para la Cooperación y el Desarrollo Económicos
    'Non-OECD',        # Países que no son OECD
    'Total',           # Cualquier total (ej: "Total North America")
    'of which',        # Subcategorías
    'Other',           # Agrupación de "otros países"
    'Europe',          # Total europeo (no países individuales)
    'European Union',  # La UE como bloque
    'EU',              # Abreviatura de European Union
    'Asia',            # Total asiático
    'Africa',          # Total africano
    'Middle East',     # Total de Medio Oriente
    'CIS',             # Comunidad de Estados Independientes
    'S. & Cent. America'  # Total de Sur y Centroamérica
]

# Crear un patrón de búsqueda con todas estas palabras
# El símbolo | significa "O" - busca cualquiera de estas palabras
exclusion_pattern = '|'.join(aggregations_to_exclude)

# Aplicar el filtro
# El símbolo ~ significa "NOT" (negación)
# Queremos mantener solo las filas que NO contienen estas palabras
gas_analysis = gas_analysis[~gas_analysis['País'].str.contains(
    exclusion_pattern, 
    case=False,  # No importa si está en mayúsculas o minúsculas
    na=False     # Los valores nulos (NaN) se tratan como False
)]

print(f"✅ Después de filtrar agregaciones: {len(gas_analysis)} países reales")
print(f"   Se eliminaron: {len(gas_2020) - len(gas_analysis)} filas de totales/agrupaciones")
# ============================================================================

# Ahora continuamos con el cálculo del R/P Ratio
# Reservas en Tcm (trillions), Producción en Bcm (billions) por año
# Como 1 Tcm = 1000 Bcm, multiplicamos las reservas por 1000
gas_analysis['RP_Ratio_Years'] = (gas_analysis['Reservas_Tcm'] * 1000) / gas_analysis['Produccion_Bcm']

# Los valores infinitos pueden aparecer si un país tiene reservas pero producción cero
# Los reemplazamos con NaN (Not a Number) para evitar problemas en los gráficos
gas_analysis['RP_Ratio_Years'] = gas_analysis['RP_Ratio_Years'].replace([np.inf, -np.inf], np.nan)

print("✅ R/P Ratio calculado para gas natural")
print(f"   Total mundial: {gas_2020['Reservas_Tcm'].sum():.1f} Tcm")

# Verificación: mostrar los Top 5 países
print("\n🏆 Top 5 países por reservas de gas:")
for idx, row in gas_analysis.nlargest(5, 'Reservas_Tcm').iterrows():
    print(f"   {row['País']}: {row['Reservas_Tcm']:.1f} Tcm ({row['RP_Ratio_Years']:.0f} años)")

# Verificación adicional: asegurarnos de que no hay agregaciones
print("\n📋 Verificación - Primeros 10 países en el análisis:")
for i, pais in enumerate(gas_analysis['País'].head(10), 1):
    print(f"   {i:2d}. {pais}")
Reservas de gas cargadas: 56 registros iniciales
Usando datos de producción del año: 2023
Producción de gas cargada: 59 registros
Datos combinados: 52 registros antes de filtrar
✅ Después de filtrar agregaciones: 46 países reales
   Se eliminaron: 10 filas de totales/agrupaciones
✅ R/P Ratio calculado para gas natural
   Total mundial: 564.8 Tcm

🏆 Top 5 países por reservas de gas:
   Russian Federation: 37.4 Tcm (64 años)
   Iran: 32.1 Tcm (124 años)
   Qatar: 24.7 Tcm (136 años)
   Turkmenistan: 13.6 Tcm (178 años)
   US: 12.6 Tcm (12 años)

📋 Verificación - Primeros 10 países en el análisis:
    1. Canada
    2. Mexico
    3. US
    4. Argentina
    5. Bolivia
    6. Brazil
    7. Colombia
    8. Peru
    9. Trinidad & Tobago
   10. Venezuela
In [196]:
# Top 15 países de gas
top15_gas = gas_analysis.nlargest(15, 'Reservas_Tcm').sort_values('Reservas_Tcm')

# Crear figura igual que con petróleo
fig_gas = make_subplots(
    rows=1, cols=3,
    subplot_titles=(
        'Reservas Probadas<br><sub>(Tcm)</sub>',
        'Producción<br><sub>(Bcm/año)</sub>',
        '¿Cuánto Durará?<br><sub>(Años)</sub>'
    ),
    column_widths=[0.3, 0.3, 0.4],
    horizontal_spacing=0.08
)

# Panel 1: Reservas (verde para diferenciarlo del petróleo)
fig_gas.add_trace(go.Bar(
    y=top15_gas['País'],
    x=top15_gas['Reservas_Tcm'],
    orientation='h',
    marker_color='rgb(50, 171, 96)',  # Verde
    showlegend=False,
    text=top15_gas['Reservas_Tcm'].round(1),
    textposition='outside'
), row=1, col=1)

# Panel 2: Producción (naranja)
fig_gas.add_trace(go.Bar(
    y=top15_gas['País'],
    x=top15_gas['Produccion_Bcm'],
    orientation='h',
    marker_color='rgb(255, 152, 0)',  # Naranja
    showlegend=False,
    text=top15_gas['Produccion_Bcm'].round(0),
    textposition='outside'
), row=1, col=2)

# Panel 3: R/P Ratio
fig_gas.add_trace(go.Scatter(
    y=top15_gas['País'],
    x=top15_gas['RP_Ratio_Years'],
    mode='lines+markers',
    marker=dict(size=10, color='rgb(50, 171, 96)', line=dict(width=2, color='white')),
    line=dict(width=2, color='rgb(50, 171, 96)'),
    showlegend=False,
    text=top15_gas['RP_Ratio_Years'].round(0).astype(str) + 'Y',
    textposition='middle right'
), row=1, col=3)

fig_gas.update_layout(
    title='🔥 Top 15 Países - Reservas de Gas Natural',
    height=700,
    plot_bgcolor='white'
)
fig_gas.update_xaxes(showgrid=True, gridcolor='lightgray')
fig_gas.update_yaxes(showgrid=False, row=1, col=1)
fig_gas.update_yaxes(showticklabels=False, row=1, col=2)
fig_gas.update_yaxes(showticklabels=False, row=1, col=3)

fig_gas.show()

📊 MÓDULO 3: Análisis de Producción y Consumo¶

Ahora vamos a responder: ¿Qué países producen más de lo que consumen? (exportadores netos) y ¿Cuáles consumen más de lo que producen? (importadores netos)

Esto es crucial para entender la geopolítica energética global.

3.1 Balance Energético de Petróleo¶

In [197]:
# Obtener consumo de petróleo 2020
# El consumo nos dice cuánto petróleo usa cada país internamente

oil_cons = df_oil_consumption[['Continent', df_oil_consumption.columns[1], '2020']].copy()
oil_cons.columns = ['Continente', 'País', 'Consumo_Mbbl_dia']

# Limpiar datos de consumo (convertir formato europeo a formato Python)
oil_cons['Consumo_Mbbl_dia'] = oil_cons['Consumo_Mbbl_dia'].astype(str).str.replace(',', '.')
oil_cons['Consumo_Mbbl_dia'] = pd.to_numeric(oil_cons['Consumo_Mbbl_dia'], errors='coerce')
oil_cons = oil_cons.dropna()

print(f"Datos de consumo cargados: {len(oil_cons)} registros")

# Combinar producción y consumo
# Esto une dos tablas: cuánto produce cada país y cuánto consume
# El merge por 'País' hace que cada fila tenga ambos valores para el mismo país
balance_oil = oil_prod_2020[['País', 'Produccion_Mbbl_dia']].merge(
    oil_cons[['País', 'Consumo_Mbbl_dia']], 
    on='País'
)

print(f"Datos combinados (producción + consumo): {len(balance_oil)} registros iniciales")

# ============================================================================
# FILTRAR AGREGACIONES Y TOTALES
# ============================================================================
# Este filtro es CRÍTICO aquí porque estamos calculando balances
# Si dejamos entrar "World" o "OPEC", distorsionaría completamente el análisis

# La misma lista de exclusiones que hemos usado consistentemente
aggregations_to_exclude = [
    'World',           # El mundo produce lo que consume (balance = 0)
    'OPEC',            # Suma de países ya listados individualmente
    'Non-OPEC',        # Suma de otros países ya listados
    'OECD',            # Organización de países desarrollados
    'Non-OECD',        # Países que no son OECD
    'Total',           # Cualquier total regional
    'of which',        # Subcategorías
    'Other',           # Agrupación de "otros"
    'Europe',          # Total europeo
    'European Union',  # La UE como bloque
    'EU',              # Abreviatura
    'Asia',            # Total asiático
    'Africa',          # Total africano
    'Middle East',     # Total de Medio Oriente
    'CIS',             # Ex-repúblicas soviéticas
    'S. & Cent. America'  # Total de América del Sur y Central
]

# Crear patrón de búsqueda
exclusion_pattern = '|'.join(aggregations_to_exclude)

# Aplicar filtro
# ~ significa "NOT" - queremos solo países que NO coincidan con el patrón
balance_oil = balance_oil[~balance_oil['País'].str.contains(
    exclusion_pattern,
    case=False,  # Ignora mayúsculas/minúsculas
    na=False     # Trata valores nulos como False
)]

print(f"✅ Después de filtrar: {len(balance_oil)} países reales")
print(f"   Se eliminaron: {len(oil_prod_2020) - len(balance_oil)} filas de agregaciones")
# ============================================================================

# Ahora sí, calcular el balance
# Balance = Producción - Consumo
# Si el balance es POSITIVO: el país produce más de lo que consume (EXPORTADOR)
# Si el balance es NEGATIVO: el país consume más de lo que produce (IMPORTADOR)
balance_oil['Balance'] = balance_oil['Produccion_Mbbl_dia'] - balance_oil['Consumo_Mbbl_dia']

# Crear una columna que clasifique cada país
# Esta columna tendrá el texto "Exportador Neto" o "Importador Neto"
balance_oil['Tipo'] = balance_oil['Balance'].apply(
    lambda x: 'Exportador Neto' if x > 0 else 'Importador Neto'
)

# También es útil calcular el porcentaje
# ¿Qué porcentaje de su producción exportan? o ¿Qué porcentaje de su consumo importan?
balance_oil['Balance_Porcentaje'] = (
    balance_oil['Balance'] / balance_oil['Produccion_Mbbl_dia'] * 100
).round(1)

print("\n✅ Balance energético calculado")
print(f"   Países analizados: {len(balance_oil)}")

# Estadísticas generales
exportadores = balance_oil[balance_oil['Balance'] > 0]
importadores = balance_oil[balance_oil['Balance'] < 0]

print(f"\n📊 Resumen del Balance Energético:")
print(f"   Exportadores netos: {len(exportadores)} países")
print(f"   Importadores netos: {len(importadores)} países")

# Mostrar los Top 5 exportadores
print(f"\n🏆 Top 5 EXPORTADORES (producen mucho más de lo que consumen):")
for idx, row in balance_oil.nlargest(5, 'Balance').iterrows():
    print(f"   {row['País']}: +{row['Balance']:.0f} Mbbl/día "
          f"({row['Balance_Porcentaje']:.0f}% de su producción)")

# Mostrar los Top 5 importadores
print(f"\n📥 Top 5 IMPORTADORES (consumen mucho más de lo que producen):")
for idx, row in balance_oil.nsmallest(5, 'Balance').iterrows():
    print(f"   {row['País']}: {row['Balance']:.0f} Mbbl/día "
          f"(déficit del {abs(row['Balance_Porcentaje']):.0f}%)")

# Verificación visual de los primeros 10 países
print("\n📋 Verificación - Primeros 10 países en el balance:")
for i, row in balance_oil.head(10).iterrows():
    simbolo = "📤" if row['Balance'] > 0 else "📥"
    print(f"   {simbolo} {row['País']}: Balance = {row['Balance']:.0f} Mbbl/día")
Datos de consumo cargados: 95 registros
Datos combinados (producción + consumo): 43 registros iniciales
✅ Después de filtrar: 36 países reales
   Se eliminaron: 26 filas de agregaciones

✅ Balance energético calculado
   Países analizados: 36

📊 Resumen del Balance Energético:
   Exportadores netos: 22 países
   Importadores netos: 14 países

🏆 Top 5 EXPORTADORES (producen mucho más de lo que consumen):
   Saudi Arabia: +7602 Mbbl/día (69% de su producción)
   Russian Federation: +7362 Mbbl/día (69% de su producción)
   Iraq: +3421 Mbbl/día (83% de su producción)
   Canada: +2957 Mbbl/día (58% de su producción)
   United Arab Emirates: +2825 Mbbl/día (76% de su producción)

📥 Top 5 IMPORTADORES (consumen mucho más de lo que producen):
   China: -10503 Mbbl/día (déficit del 269%)
   India: -3943 Mbbl/día (déficit del 496%)
   Italy: -946 Mbbl/día (déficit del 837%)
   Thailand: -733 Mbbl/día (déficit del 174%)
   US: -685 Mbbl/día (déficit del 4%)

📋 Verificación - Primeros 10 países en el balance:
   📤 Canada: Balance = 2957 Mbbl/día
   📤 Mexico: Balance = 308 Mbbl/día
   📥 US: Balance = -685 Mbbl/día
   📤 Argentina: Balance = 214 Mbbl/día
   📤 Brazil: Balance = 762 Mbbl/día
   📤 Colombia: Balance = 436 Mbbl/día
   📤 Ecuador: Balance = 276 Mbbl/día
   📥 Peru: Balance = -70 Mbbl/día
   📤 Trinidad & Tobago: Balance = 46 Mbbl/día
   📤 Venezuela: Balance = 446 Mbbl/día
In [198]:
# Gráfico de barras de balance (positivo vs negativo)
# Tomamos Top 10 exportadores y Top 10 importadores

top10_exp = balance_oil.nlargest(10, 'Balance')
top10_imp = balance_oil.nsmallest(10, 'Balance')
balance_top20 = pd.concat([top10_exp, top10_imp]).sort_values('Balance')

# Crear gráfico
fig_balance = go.Figure()

# Colores: verde para exportadores, rojo para importadores
colors = ['green' if x > 0 else 'red' for x in balance_top20['Balance']]

fig_balance.add_trace(go.Bar(
    y=balance_top20['País'],
    x=balance_top20['Balance'],
    orientation='h',
    marker_color=colors,
    text=balance_top20['Balance'].round(0),
    textposition='outside'
))

fig_balance.update_layout(
    title='⚖️ Balance Energético de Petróleo<br><sub>Producción - Consumo (Mbbl/día)</sub>',
    xaxis_title='Balance (positivo = exportador)',
    height=600,
    showlegend=False,
    plot_bgcolor='white'
)
fig_balance.update_xaxes(showgrid=True, gridcolor='lightgray', zeroline=True, zerolinewidth=2)

fig_balance.show()

📊 MÓDULO 4: Análisis Integrado¶

Ahora vamos a comparar petróleo y gas lado a lado, y crear un dashboard interactivo.

4.1 Comparación Petróleo vs Gas¶

In [199]:
# Combinar datos de petróleo y gas por país
comparison = oil_analysis[['País', 'Reservas_Bbbl', 'RP_Ratio_Years']].merge(
    gas_analysis[['País', 'Reservas_Tcm', 'RP_Ratio_Years']],
    on='País',
    suffixes=('_Oil', '_Gas')
)

print(f"✅ {len(comparison)} países con ambos recursos")
print("\\nPaíses con más petróleo que gas (ratio):")
comparison['Oil_Gas_Ratio'] = comparison['Reservas_Bbbl'] / (comparison['Reservas_Tcm'] + 0.001)
for _, row in comparison.nlargest(5, 'Oil_Gas_Ratio').iterrows():
    print(f"   {row['País']}: Petróleo/Gas = {row['Oil_Gas_Ratio']:.1f}")
✅ 37 países con ambos recursos
\nPaíses con más petróleo que gas (ratio):
   Canada: Petróleo/Gas = 70.0
   Kuwait: Petróleo/Gas = 59.7
   Saudi Arabia: Petróleo/Gas = 49.6
   Venezuela: Petróleo/Gas = 48.2
   Iraq: Petróleo/Gas = 41.4
In [200]:
# Gráfico de dispersión: Reservas de Petróleo vs Gas
fig_scatter = px.scatter(
    comparison,
    x='Reservas_Tcm',
    y='Reservas_Bbbl',
    size='Reservas_Bbbl',  # Tamaño de burbuja según reservas de petróleo
    hover_name='País',
    title='🔷 Petróleo vs Gas: ¿Qué países tienen más de cada uno?',
    labels={
        'Reservas_Tcm': 'Reservas de Gas (Tcm)',
        'Reservas_Bbbl': 'Reservas de Petróleo (Bbbl)'
    },
    color='Oil_Gas_Ratio',
    color_continuous_scale='RdYlGn_r'  # Rojo-Amarillo-Verde invertido
)

fig_scatter.update_layout(height=600)
fig_scatter.show()
In [201]:
# Vamos a crear un diagrama de Sankey que muestre flujos de petróleo
# Desde países PRODUCTORES → hacia CONSUMO o EXPORTACIÓN

# Primero, tomemos los Top 10 exportadores y Top 10 importadores
top_exportadores = balance_oil[balance_oil['Balance'] > 0].nlargest(10, 'Balance')
top_importadores = balance_oil[balance_oil['Balance'] < 0].nsmallest(10, 'Balance')

print("🔄 Preparando datos para diagrama de Sankey...")
print(f"   Exportadores: {len(top_exportadores)}")
print(f"   Importadores: {len(top_importadores)}")

# Los diagramas de Sankey necesitan tres listas:
# 1. source: lista de índices de los nodos de ORIGEN
# 2. target: lista de índices de los nodos de DESTINO  
# 3. value: lista de valores (magnitud del flujo)

# Primero creamos una lista de TODOS los nodos (países)
# Un nodo es simplemente un punto en el diagrama donde las líneas se conectan
all_nodes = []

# Añadimos los exportadores con una etiqueta especial
for pais in top_exportadores['País']:
    all_nodes.append(f"🛢️ {pais}")  # Añadimos emoji para distinguir exportadores

# Añadimos los importadores con diferente etiqueta
for pais in top_importadores['País']:
    all_nodes.append(f"📥 {pais}")  # Emoji diferente para importadores

print(f"\n📊 Nodos creados: {len(all_nodes)} países")

# Ahora creamos las tres listas que Plotly necesita
source = []  # Lista de índices de origen
target = []  # Lista de índices de destino
value = []   # Lista de valores de flujo

# Para cada exportador, creamos flujos hacia una categoría "Mercado Global"
# En un análisis más detallado, podrías tener datos específicos de quién
# exporta a quién, pero para este ejemplo simplificado mostraremos
# el concepto de flujos hacia el mercado global

# Primero añadimos un nodo especial para "Mercado Global"
all_nodes.append("🌍 Mercado Global")
mercado_global_index = len(all_nodes) - 1

# Crear flujos desde cada exportador hacia el mercado global
for i, (idx, row) in enumerate(top_exportadores.iterrows()):
    # i es el índice del exportador en nuestra lista de nodos
    # El valor del flujo es su balance de exportación
    source.append(i)
    target.append(mercado_global_index)
    value.append(abs(row['Balance']))  # abs() para tener valores positivos

# Ahora creamos flujos desde el mercado global hacia cada importador
for i, (idx, row) in enumerate(top_importadores.iterrows()):
    # Los importadores están después de los exportadores en la lista
    importador_index = len(top_exportadores) + i
    
    source.append(mercado_global_index)
    target.append(importador_index)
    value.append(abs(row['Balance']))  # abs() porque el balance es negativo

print(f"\n✅ Flujos creados: {len(source)} conexiones")
🔄 Preparando datos para diagrama de Sankey...
   Exportadores: 10
   Importadores: 10

📊 Nodos creados: 20 países

✅ Flujos creados: 20 conexiones
In [202]:
# ============================================================================
# PREPARAR BALANCE ENERGÉTICO DE GAS NATURAL
# ============================================================================
# Vamos a replicar el mismo análisis que hicimos con petróleo pero para gas

print("🔥 Preparando balance de GAS NATURAL...")
print("="*70)

# Primero necesitamos los datos de consumo de gas
# Buscamos el año más reciente disponible en los datos de consumo
year_cols_gas_cons = [col for col in df_gas_consumption.columns if col.isdigit()]
latest_year_cons = max(year_cols_gas_cons, key=lambda x: int(x))

print(f"📅 Usando datos de consumo de gas del año: {latest_year_cons}")

# Extraer consumo de gas
gas_cons = df_gas_consumption[['Continent', df_gas_consumption.columns[1], latest_year_cons]].copy()
gas_cons.columns = ['Continente', 'País', 'Consumo_Bcm']

# Limpiar datos (convertir formato europeo a formato Python)
gas_cons['Consumo_Bcm'] = gas_cons['Consumo_Bcm'].astype(str).str.replace(',', '.')
gas_cons['Consumo_Bcm'] = pd.to_numeric(gas_cons['Consumo_Bcm'], errors='coerce')
gas_cons = gas_cons.dropna()

print(f"   Datos de consumo cargados: {len(gas_cons)} registros")

# Ahora combinamos la producción de gas que ya tenemos con el consumo
# Recuerda que ya calculamos gas_prod anteriormente en el notebook
balance_gas = gas_prod[['País', 'Produccion_Bcm']].merge(
    gas_cons[['País', 'Consumo_Bcm']], 
    on='País'
)

print(f"   Producción y consumo combinados: {len(balance_gas)} registros iniciales")

# ============================================================================
# APLICAR FILTRO DE EXCLUSIÓN (MUY IMPORTANTE)
# ============================================================================
# La misma lista de agregaciones que hemos usado consistentemente
aggregations_to_exclude = [
    'World', 'OPEC', 'Non-OPEC', 'OECD', 'Non-OECD',
    'Total', 'of which', 'Other', 'Europe', 'European Union', 'EU',
    'Asia', 'Africa', 'Middle East', 'CIS', 'S. & Cent. America'
]

exclusion_pattern = '|'.join(aggregations_to_exclude)

# Filtrar las agregaciones
balance_gas = balance_gas[~balance_gas['País'].str.contains(
    exclusion_pattern,
    case=False,
    na=False
)]

print(f"✅ Después de filtrar agregaciones: {len(balance_gas)} países reales")

# Calcular el balance para gas
# Balance = Producción - Consumo (igual que con petróleo)
balance_gas['Balance'] = balance_gas['Produccion_Bcm'] - balance_gas['Consumo_Bcm']

# Clasificar como exportador o importador
balance_gas['Tipo'] = balance_gas['Balance'].apply(
    lambda x: 'Exportador Neto' if x > 0 else 'Importador Neto'
)

# Estadísticas rápidas
exportadores_gas = balance_gas[balance_gas['Balance'] > 0]
importadores_gas = balance_gas[balance_gas['Balance'] < 0]

print(f"\n📊 Balance de Gas Natural calculado:")
print(f"   Exportadores netos: {len(exportadores_gas)} países")
print(f"   Importadores netos: {len(importadores_gas)} países")

# Mostrar los principales
print(f"\n🏆 Top 5 Exportadores de GAS:")
for _, row in balance_gas.nlargest(5, 'Balance').iterrows():
    print(f"   {row['País']}: +{row['Balance']:.0f} Bcm/año")

print(f"\n📥 Top 5 Importadores de GAS:")
for _, row in balance_gas.nsmallest(5, 'Balance').iterrows():
    print(f"   {row['País']}: {row['Balance']:.0f} Bcm/año")
🔥 Preparando balance de GAS NATURAL...
======================================================================
📅 Usando datos de consumo de gas del año: 2024
   Datos de consumo cargados: 91 registros
   Producción y consumo combinados: 50 registros iniciales
✅ Después de filtrar agregaciones: 42 países reales

📊 Balance de Gas Natural calculado:
   Exportadores netos: 18 países
   Importadores netos: 24 países

🏆 Top 5 Exportadores de GAS:
   Qatar: +134 Bcm/año
   US: +131 Bcm/año
   Australia: +114 Bcm/año
   Norway: +113 Bcm/año
   Russian Federation: +109 Bcm/año

📥 Top 5 Importadores de GAS:
   China: -200 Bcm/año
   Germany: -75 Bcm/año
   Mexico: -62 Bcm/año
   Italy: -56 Bcm/año
   India: -39 Bcm/año
In [203]:
# Verificación rápida: asegurarnos que balance_oil también está filtrado
# Si ya lo ejecutaste con el filtro, esto no hará nada
# Si no, lo filtrará ahora

print("\n🛢️ Verificando balance de PETRÓLEO...")

# Aplicar el mismo filtro si no se ha aplicado antes
if 'World' in balance_oil['País'].values or 'OPEC' in balance_oil['País'].values:
    print("   ⚠️ Detectadas agregaciones, aplicando filtro...")
    balance_oil = balance_oil[~balance_oil['País'].str.contains(
        exclusion_pattern,
        case=False,
        na=False
    )]
    # Recalcular tipo si es necesario
    balance_oil['Tipo'] = balance_oil['Balance'].apply(
        lambda x: 'Exportador Neto' if x > 0 else 'Importador Neto'
    )
    print(f"   ✅ Filtrado: {len(balance_oil)} países reales")
else:
    print(f"   ✅ Ya filtrado: {len(balance_oil)} países reales")

print("\n🎯 Ambos datasets listos para comparación")
🛢️ Verificando balance de PETRÓLEO...
   ✅ Ya filtrado: 36 países reales

🎯 Ambos datasets listos para comparación
In [204]:
# ============================================================================
# CREAR DIAGRAMAS DE SANKEY COMPARATIVOS
# ============================================================================
print("\n🎨 Creando diagramas de Sankey comparativos...")
print("="*70)

# ESTRATEGIA: Usar los mismos países en ambos diagramas para comparabilidad
# Vamos a tomar el Top 8 de exportadores e importadores de cada recurso
# y luego combinar las listas para tener un conjunto único de países

# Top 8 exportadores e importadores de PETRÓLEO
top8_exp_oil = balance_oil[balance_oil['Balance'] > 0].nlargest(8, 'Balance')
top8_imp_oil = balance_oil[balance_oil['Balance'] < 0].nsmallest(8, 'Balance')

# Top 8 exportadores e importadores de GAS
top8_exp_gas = balance_gas[balance_gas['Balance'] > 0].nlargest(8, 'Balance')
top8_imp_gas = balance_gas[balance_gas['Balance'] < 0].nsmallest(8, 'Balance')

# Crear un conjunto único de países (usar set para evitar duplicados)
# Convertimos a set y luego de vuelta a list para mantener países únicos
exportadores_unicos = list(set(
    list(top8_exp_oil['País']) + list(top8_exp_gas['País'])
))

importadores_unicos = list(set(
    list(top8_imp_oil['País']) + list(top8_imp_gas['País'])
))

print(f"\n📋 Países seleccionados para la comparación:")
print(f"   Exportadores únicos: {len(exportadores_unicos)} países")
print(f"   Importadores únicos: {len(importadores_unicos)} países")

# Ordenar alfabéticamente para consistencia visual
exportadores_unicos.sort()
importadores_unicos.sort()

print(f"\n🟢 Exportadores: {', '.join(exportadores_unicos[:5])}...")
print(f"🔴 Importadores: {', '.join(importadores_unicos[:5])}...")
🎨 Creando diagramas de Sankey comparativos...
======================================================================

📋 Países seleccionados para la comparación:
   Exportadores únicos: 13 países
   Importadores únicos: 12 países

🟢 Exportadores: Algeria, Australia, Canada, Iraq, Kazakhstan...
🔴 Importadores: Australia, China, Germany, India, Indonesia...
In [205]:
# ============================================================================
# FUNCIÓN AUXILIAR PARA CREAR DATOS DE SANKEY
# ============================================================================
# Esta función convierte nuestros datos de balance en el formato que Sankey necesita
# La creamos como función para no repetir el mismo código dos veces

def preparar_datos_sankey(balance_df, exportadores_list, importadores_list):
    """
    Prepara los datos en formato Sankey (source, target, value)
    
    Parámetros:
    - balance_df: DataFrame con columnas 'País' y 'Balance'
    - exportadores_list: lista de países exportadores a incluir
    - importadores_list: lista de países importadores a incluir
    
    Retorna:
    - all_nodes: lista de etiquetas de todos los nodos
    - source: lista de índices de origen
    - target: lista de índices de destino
    - value: lista de valores de flujo
    """
    
    # Crear lista de todos los nodos
    # Los exportadores van primero, luego los importadores
    all_nodes = []
    
    # Añadir exportadores con emoji verde
    for pais in exportadores_list:
        all_nodes.append(f"📤 {pais}")
    
    # Añadir nodo central "Mercado Global"
    all_nodes.append("🌍 Mercado")
    mercado_index = len(all_nodes) - 1
    
    # Añadir importadores con emoji rojo
    for pais in importadores_list:
        all_nodes.append(f"📥 {pais}")
    
    # Inicializar las tres listas que Sankey necesita
    source = []
    target = []
    value = []
    
    # Crear flujos desde exportadores hacia el mercado
    for i, pais in enumerate(exportadores_list):
        # Buscar el balance de este país en el DataFrame
        pais_data = balance_df[balance_df['País'] == pais]
        
        # Si el país existe en los datos y tiene balance positivo
        if len(pais_data) > 0:
            balance_value = pais_data.iloc[0]['Balance']
            if balance_value > 0:
                source.append(i)  # Índice del exportador
                target.append(mercado_index)  # Índice del mercado
                value.append(balance_value)
    
    # Crear flujos desde el mercado hacia importadores
    for i, pais in enumerate(importadores_list):
        # El índice del importador en all_nodes
        # Es: cantidad de exportadores + 1 (el mercado) + posición en lista de importadores
        importador_index = len(exportadores_list) + 1 + i
        
        # Buscar el balance de este país
        pais_data = balance_df[balance_df['País'] == pais]
        
        # Si el país existe y tiene balance negativo (importador)
        if len(pais_data) > 0:
            balance_value = pais_data.iloc[0]['Balance']
            if balance_value < 0:
                source.append(mercado_index)  # Desde el mercado
                target.append(importador_index)  # Hacia el importador
                value.append(abs(balance_value))  # Valor absoluto
    
    return all_nodes, source, target, value

# Preparar datos para PETRÓLEO
print("\n🛢️ Preparando datos de Sankey para PETRÓLEO...")
nodes_oil, source_oil, target_oil, value_oil = preparar_datos_sankey(
    balance_oil, 
    exportadores_unicos, 
    importadores_unicos
)
print(f"   ✅ {len(source_oil)} flujos creados")

# Preparar datos para GAS
print("🔥 Preparando datos de Sankey para GAS NATURAL...")
nodes_gas, source_gas, target_gas, value_gas = preparar_datos_sankey(
    balance_gas,
    exportadores_unicos,
    importadores_unicos
)
print(f"   ✅ {len(source_gas)} flujos creados")
🛢️ Preparando datos de Sankey para PETRÓLEO...
   ✅ 20 flujos creados
🔥 Preparando datos de Sankey para GAS NATURAL...
   ✅ 17 flujos creados
In [206]:
# ============================================================================
# CREAR FIGURA CON DOS DIAGRAMAS DE SANKEY
# ============================================================================

# Importar la capacidad de crear Sankey en subplots
from plotly import graph_objects as go
from plotly.subplots import make_subplots

print("\n🎨 Construyendo visualización comparativa...")

# Crear figura con dos columnas (una para petróleo, otra para gas)
fig_comparison = make_subplots(
    rows=1, 
    cols=2,
    subplot_titles=(
        '🛢️ PETRÓLEO<br><sub>Flujos de Exportación/Importación (Mbbl/día)</sub>',
        '🔥 GAS NATURAL<br><sub>Flujos de Exportación/Importación (Bcm/año)</sub>'
    ),
    # Especificar que son diagramas de tipo Sankey
    specs=[[{"type": "sankey"}, {"type": "sankey"}]],
    horizontal_spacing=0.05  # Poco espacio entre diagramas
)

# Colores consistentes para ambos diagramas
# Verde para exportadores, azul para mercado, rojo para importadores
num_exportadores = len(exportadores_unicos)
num_importadores = len(importadores_unicos)

node_colors = (
    ['rgba(46, 125, 50, 0.8)'] * num_exportadores +  # Verde para exportadores
    ['rgba(25, 118, 210, 0.8)'] +  # Azul para mercado global
    ['rgba(211, 47, 47, 0.8)'] * num_importadores  # Rojo para importadores
)

# DIAGRAMA 1: PETRÓLEO (columna izquierda)
fig_comparison.add_trace(
    go.Sankey(
        node=dict(
            pad=15,
            thickness=20,
            line=dict(color="white", width=2),
            label=nodes_oil,
            color=node_colors
        ),
        link=dict(
            source=source_oil,
            target=target_oil,
            value=value_oil,
            color='rgba(150, 150, 150, 0.3)'  # Gris transparente para las líneas
        )
    ),
    row=1, col=1
)

# DIAGRAMA 2: GAS NATURAL (columna derecha)
fig_comparison.add_trace(
    go.Sankey(
        node=dict(
            pad=15,
            thickness=20,
            line=dict(color="white", width=2),
            label=nodes_gas,
            color=node_colors  # Mismos colores para comparabilidad
        ),
        link=dict(
            source=source_gas,
            target=target_gas,
            value=value_gas,
            color='rgba(150, 150, 150, 0.3)'
        )
    ),
    row=1, col=2
)

# Configurar el diseño general
fig_comparison.update_layout(
    title=dict(
        text='🌍 Comparación de Flujos Energéticos: Petróleo vs Gas Natural<br>' +
             '<sub>Principales exportadores e importadores netos (2020-2023)</sub>',
        font=dict(size=22, family='Arial'),
        x=0.5,
        xanchor='center'
    ),
    font=dict(size=11),
    height=900,  # Altura generosa para ver bien los flujos
    showlegend=False,
    plot_bgcolor='white',
    paper_bgcolor='white'
)

print("✅ Diagramas comparativos creados")
print("\n💡 CÓMO INTERPRETAR LA VISUALIZACIÓN:")
print("   • Los bloques VERDES son países exportadores netos")
print("   • El bloque AZUL central representa el mercado global")
print("   • Los bloques ROJOS son países importadores netos")
print("   • El GROSOR de cada línea es proporcional al volumen comerciado")
print("   • Compara el mismo país entre ambos diagramas para ver diferencias")
print("\n📍 Pasa el mouse sobre cualquier elemento para ver valores exactos")
print("🔍 BUSCA PATRONES: ¿Qué países tienen perfiles diferentes en petróleo vs gas?")

fig_comparison.show()
🎨 Construyendo visualización comparativa...
✅ Diagramas comparativos creados

💡 CÓMO INTERPRETAR LA VISUALIZACIÓN:
   • Los bloques VERDES son países exportadores netos
   • El bloque AZUL central representa el mercado global
   • Los bloques ROJOS son países importadores netos
   • El GROSOR de cada línea es proporcional al volumen comerciado
   • Compara el mismo país entre ambos diagramas para ver diferencias

📍 Pasa el mouse sobre cualquier elemento para ver valores exactos
🔍 BUSCA PATRONES: ¿Qué países tienen perfiles diferentes en petróleo vs gas?